<?php
declare(strict_types=1);

namespace App;

use App\AdminApi\Module\System\Service\CachingService;
use App\AdminApi\Module\System\Service\ConfigureService;
use Hyperf\Context\ApplicationContext;
use Hyperf\Logger\LoggerFactory;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface;
use Zms\Exception\PrintException;
use function Hyperf\Config\config;
use function Hyperf\Support\env;

/**
 * 系统工具类
 * 提供了系统中常用的功能封装，包括日志、缓存、事件分发、配置管理等。
 */
class Sys
{
    /**
     * 服务列表
     */
    const SERVER = [
        'JSON_API' => 'json-api'
    ];

    /**
     * 应用配置
     */
    const APP = [
        'ADMIN' => [
            'DESC' => '后台接口', // 应用描述
            'NAME' => 'admin',   // 应用名称
            'SERVER' => self::SERVER['JSON_API'], // 所属服务
            'GUARD' => 'admin',  // 认证体系
        ]
    ];

    /**
     * 获取容器中的单例实例
     * 使用此方法从依赖注入容器中获取指定类的实例。
     * 如果容器中未找到对应的类，则返回 null。
     * @template T
     * @param class-string<T> $className 要获取的类名或接口名
     * @return T|null 返回指定类的实例，如果未找到则返回 null
     */
    public static function container(string $className): mixed
    {
        try {
            return ApplicationContext::getContainer()->get($className);
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface) {
            return null;
        }
    }


    /**
     * 获取日志记录器实例
     * @param string $group 日志组，默认为 'default'
     * @param string $name 日志名称，默认为 'app'
     * @return LoggerInterface 返回指定的日志记录器实例
     */
    public static function log(string $group = 'default', string $name = 'app'): LoggerInterface
    {
        return self::container(LoggerFactory::class)->get($name, $group);
    }

    /**
     * 获取数据库缓存工具实例
     * @return CachingService 返回 CachingService 实例
     */
    public static function caching(): CachingService
    {
        return self::container(CachingService::class);
    }

    /**
     * 触发事件
     * @param object $event 要触发的事件对象
     * @return object|null 返回事件处理结果，如果容器中未找到 EventDispatcher，则返回 null
     */
    public static function event(object $event): ?object
    {
        try {
            return ApplicationContext::getContainer()->get(EventDispatcherInterface::class)->dispatch($event);
        } catch (NotFoundExceptionInterface|ContainerExceptionInterface) {
            return null;
        }
    }

    /**
     * 获取缓存工具实例
     * @return CacheInterface 返回 PSR 缓存接口实例
     */
    public static function cache(): CacheInterface
    {
        return self::container(CacheInterface::class);
    }

    /**
     * 打印数据到浏览器（调试用）
     * @param mixed $data 需要打印的数据
     * @throws PrintException 抛出异常以显示数据
     */
    public static function show(mixed $data): void
    {
        throw new PrintException($data);
    }

    /**
     * 检查是否处于开发模式
     * @return bool 如果当前环境为开发模式（APP_ENV 为 'dev'），返回 true；否则返回 false
     */
    public static function develop(): bool
    {
        return env('APP_ENV') === 'dev';
    }

    /**
     * 获取系统配置
     * @param string $key 配置键名
     * @param mixed $default 默认值（如果配置不存在时返回）
     * @return mixed 返回配置值或默认值
     */
    public static function conf(string $key, mixed $default = null): mixed
    {
        return self::container(ConfigureService::class)->get($key, $default);
    }

    /**
     * 获取资源保存目录
     * @param string $path
     * @return string
     */
    public static function getAssetsPath(string $path): string
    {
        return config('server.settings.document_root') . '/zms-assets/' . ltrim($path, '/');
    }


    /**
     * 获取资源URL
     * @param string $path
     * @return string
     */
    public static function getAssetsUrl(string $path): string
    {
        $domain = Sys::conf('system.domain') ?: '';
        $assets_path = config('server.settings.document_root');
        if (str_starts_with($path, $assets_path)) {
            return $domain . substr($path, strlen($assets_path));
        }
        return $domain . '/' . ltrim($path, '/');
    }
}